package com.justgame.project.cloud.common.util;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public class RedisDistributedLock {
    private static final long DEFAULT_EXPIRE_TIME = 5000; // 默认过期时间为 5 秒
    private static final long DEFAULT_RETRY_INTERVAL = 100; // 默认自旋重试时间间隔为 100 毫秒

    private final RedisTemplate<String, Object> redisTemplate;

    public RedisDistributedLock(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 尝试获取分布式锁
     *
     * @param lockKey   锁
     * @param requestId 请求标识
     * @param expire    超期时间（毫秒）
     * @return 是否获取成功
     */
    public boolean tryLock(String lockKey, String requestId, long expire) {
        // 使用 setIfAbsent 方法实现分布式锁
        Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, requestId, expire, TimeUnit.MILLISECONDS);
        return result != null && result;
    }

    /**
     * 带超时时间的自旋获取分布式锁
     *
     * @param lockKey        锁
     * @param requestId      请求标识
     * @param expire         超期时间（毫秒）
     * @param timeout        等待超时时间（毫秒）
     * @param retryInterval  自旋重试时间间隔（毫秒）
     * @return 是否获取成功
     * @throws InterruptedException 如果自旋等待被中断
     */
    public boolean tryLock(String lockKey, String requestId, long expire, long timeout, long retryInterval) throws InterruptedException {
        long start = System.currentTimeMillis();
        long end = start + timeout;

        while (System.currentTimeMillis() < end) {
            if (tryLock(lockKey, requestId, expire)) {
                return true;
            }
            Thread.sleep(retryInterval);
        }

        return false;
    }

    /**
     * 释放分布式锁
     *
     * @param lockKey   锁
     * @param requestId 请求标识
     * @return 是否释放成功
     */
    public boolean releaseLock(String lockKey, String requestId) {
        String currentValue = (String) redisTemplate.opsForValue().get(lockKey);
        if (currentValue != null && currentValue.equals(requestId)) {
            return Boolean.TRUE.equals(redisTemplate.delete(lockKey));
        }
        return false;
    }
}
